*/
/*
- * Local APIC handling, local APIC timers
+ * Local APIC handling, local APIC timers
*
- * (c) 1999, 2000 Ingo Molnar <mingo@redhat.com>
+ * (c) 1999, 2000 Ingo Molnar <mingo@redhat.com>
*
- * Fixes
- * Maciej W. Rozycki : Bits for genuine 82489DX APICs;
- * thanks to Eric Gilmore
- * and Rolf G. Tews
- * for testing these extensively.
+ * Fixes
+ * Maciej W. Rozycki : Bits for genuine 82489DX APICs;
+ * thanks to Eric Gilmore
+ * and Rolf G. Tews
+ * for testing these extensively.
*/
value = APIC_DM_NMI;
else
value = APIC_DM_NMI | APIC_LVT_MASKED;
- if (!APIC_INTEGRATED(ver)) /* 82489DX */
+ if (!APIC_INTEGRATED(ver)) /* 82489DX */
value |= APIC_LVT_LEVEL_TRIGGER;
apic_write_around(APIC_LVT1, value);
- if (APIC_INTEGRATED(ver)) { /* !82489DX */
+ if (APIC_INTEGRATED(ver)) { /* !82489DX */
maxlvt = get_maxlvt();
- if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
+ if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
apic_write(APIC_ESR, 0);
value = apic_read(APIC_ESR);
printk("ESR value before enabling vector: %08lx\n", value);
*/
int reprogram_ac_timer(s_time_t timeout)
{
- int cpu = smp_processor_id();
- s_time_t now;
- s_time_t expire;
- u64 apic_tmict;
-
- if (timeout == 0) {
- /* XXX RN: not sure if this disables it or cause interruptto
- * go off imediately */
- apic_tmict = 0;
+ int cpu = smp_processor_id();
+ s_time_t now;
+ s_time_t expire;
+ u64 apic_tmict;
+
+ /*
+ * We use this value because we don't trust zero (we think it may just
+ * cause an immediate interrupt). At least this is guaranteed to hold it
+ * off for ages (esp. since the clock ticks on bus clock, not cpu clock!).
+ */
+ if (timeout == 0) {
+ apic_tmict = 0xffffffff;
goto reprogram;
}
now = NOW();
- expire = timeout - now; /* value from now */
+ expire = timeout - now; /* value from now */
if (expire <= 0) {
printk("APICT[%02d] Timeout in the past 0x%08X%08X > 0x%08X%08X\n",
cpu, (u32)(now>>32), (u32)now, (u32)(timeout>>32),(u32)timeout);
- return 0; /* timeout value in the past */
+ return 0; /* timeout value in the past */
}
/* conversion to bus units */
}
reprogram:
- /* programm timer */
+ /* Program the timer. */
apic_write(APIC_TMICT, (unsigned long)apic_tmict);
TRC(printk("APICT[%02d] reprog(): expire=%lld %u\n",
*/
ack_APIC_irq();
- /* call the local handler */
+ /* call the local handler */
irq_enter(cpu, 0);
- perfc_incrc(apic_timer);
+ perfc_incrc(apic_timer);
smp_local_timer_interrupt(regs);
irq_exit(cpu, 0);
u32 stime_pcc; /* cycle counter value at last timer irq */
s_time_t stime_now; /* time in ns at last timer IRQ */
-s_time_t get_s_time(void)
+static inline s_time_t __get_s_time(void)
{
- unsigned long flags;
u32 delta_tsc, low, pcc;
u64 delta;
s_time_t now;
- spin_lock_irqsave(&stime_lock, flags);
-
pcc = stime_pcc;
now = stime_now;
delta >>= 32;
delta += ((u64)delta_tsc * st_scale_i);
- spin_unlock_irqrestore(&stime_lock, flags);
+ return now + delta;
+}
- return now + delta;
+s_time_t get_s_time(void)
+{
+ s_time_t now;
+ unsigned long flags;
+ spin_lock_irqsave(&stime_lock, flags);
+ now = __get_s_time();
+ spin_unlock_irqrestore(&stime_lock, flags);
+ return now;
}
static void update_time(unsigned long foo)
{
unsigned long flags;
- u32 new_pcc;
s_time_t new_st;
unsigned long usec;
- new_st = NOW();
- rdtscl(new_pcc);
-
/* Update system time. */
spin_lock_irqsave(&stime_lock, flags);
- stime_now = new_st;
- stime_pcc=new_pcc;
+ stime_now = new_st = __get_s_time();
+ rdtscl(stime_pcc);
/* Don't reeenable IRQs until we release wctime_lock. */
spin_unlock(&stime_lock);
(u32)(timer->expires>>32), (u32)timer->expires));
return 1;
}
+
spin_lock_irqsave(&ac_timers[cpu].lock, flags);
+
/*
* Add timer to the list. If it gets added to the front we have to
* reprogramm the timer
/* just removed the head */
if (list_empty(&ac_timers[cpu].timers)) {
reprogram_ac_timer((s_time_t) 0);
+ } else {
+ timer = list_entry(ac_timers[cpu].timers.next,
+ struct ac_timer, timer_list);
+ if ( timer->expires > (NOW() + TIMER_SLOP) )
+ reprogram_ac_timer(timer->expires);
}
- /* XXX should actaully reprogramm APIC to new head */
}
} else
res = -1;
/* Sanity: is the timer list empty? */
if ( list_empty(&ac_timers[cpu].timers) ) {
- /*
- * XXX RN: This shouldn't happen, but does! Two possibilities:
- * - Race condition between removing and reseting APIC
- * - setting an APIC timeout value of 0 causes an immediate
- * timer interrupt to fire.
- * None of these should be critical!
- */
+ /* This does sometimes happen: race condition in resetting timeout? */
spin_unlock_irqrestore(&ac_timers[cpu].lock, flags);
return;
}
sched_done:
ASSERT(r_time != 0);
- ASSERT(r_time > ctx_allow);
+ ASSERT(r_time >= ctx_allow);
-#if 0
+#ifndef NDEBUG
if ( (r_time==0) || (r_time < ctx_allow)) {
printk("[%02d]: %lx\n", this_cpu, r_time);
dump_rqueue(&schedule_data[this_cpu].runqueue, "foo");
timer_redo:
schedule_data[this_cpu].s_timer.expires = now + r_time;
if (add_ac_timer(&schedule_data[this_cpu].s_timer) == 1) {
- printk("SCHED[%02d]: Shit this shouldn't happen\n", this_cpu);
+ printk("SCHED[%02d]: Shit this shouldn't happen %08x\n",
+ this_cpu, r_time);
now = NOW();
goto timer_redo;
}